# coding=utf-8
import os
import json
import time
import unicodedata
import pyarrow.parquet as pq
import traceback
from typing import Any, Dict, List, NamedTuple, Optional, Sequence, Tuple, Union


class FormatHandler():
    def __init__(self, input_path, output_path, dataset_name):
        self.input_path = input_path
        self.output_path = output_path
        self.dataset_name = dataset_name

    def get_file_list(self) -> list:
        """或取输入路径下的全部文件，可以放一些文件名判断逻辑"""
        files = os.listdir(self.input_path)
        files = [i for i in files if ".json" in i]
        return files
    
    def process_one_line(self, line, fout) -> bool:
        """处理一行数据，子类必须实现"""
        raise NotImplementedError
    
    def process_one_file(self, file_path) -> (int, int):
        """处理一份文件"""
        line_count = 0
        jump_count = 0
        with open(self.output_path, "a") as fout:
            with open(self.input_path + "/" + file_path, "r", encoding="utf-8") as fin:
                for line in fin:
                    line_count += 1
                    self.process_one_line(line, fout)
        return line_count, jump_count
    
    def process_all(self):
        """处理全部文件"""
        st = time.time()
        line_count_all = 0
        jump_count_all = 0
        file_list = self.get_file_list()
        print("[log][{}] number of files is {:d}".format(self.dataset_name, len(file_list)))
        for file in file_list:
            line_count, jump_count = 0, 0
            try:
                line_count, jump_count = self.process_one_file(file)
            except Exception as e:
                print("[exception][{}] process file {} failed: {}".format(self.dataset_name, file, e))
                print(traceback.format_exc())
            line_count_all += line_count
            jump_count_all += jump_count
        print("[log][{}] timecost is {:.2f} s!".format(self.dataset_name, time.time() - st))
        print("[log][{}] line_count is {:d}, jump_count is {:d}".format(self.dataset_name, line_count_all, jump_count_all))

    def quality_assurance(self, line) -> bool:
        """确保一段文字的基本质量, todo"""
        # 1. 字数过少
        if len(line) < 20:
            return False

        # 2. 特殊符号使用过多
        return True

    def zh_process(self, line) -> str:
        """初步的中文文本处理, todo"""
        # 0. None 处理成空字符串
        if line is None:
            return ""
        # 1. 半角全角统一。

        # 2. 英式句号、逗号转换为中式。可能并不必要。

        # 3. unicode 统一
        line = unicodedata.normalize("NFKC", line)
        # 4. 去除\r（针对 baidu_QA）
        line = line.replace("\r", "")
        # 5. 替换\n
        # line = line.replace("\n\n", "\n")
        return line
    
    def qa2txt(self, question: str, answer: str, mode: str = "qwen"):
        """将对话转换为txt文本"""
        if mode == "default":
            return "问题：\n{}\n回答：\n{}".format(question, answer)
        elif mode == "simple":
            return "{}：{}".format(question, answer)
        elif mode == "qwen":
            return "<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n" + \
                "<|im_start|>user\n{}<|im_end|>\n".format(question) + \
                "<|im_start|>assistant\n{}".format(answer)
        
    def multi_qa2txt(self, question: List[str], answer: List[str], mode="qwen"):
        """将对话转换为txt文本。针对多轮对话。"""
        if mode == "default":
            pass
        elif mode == "simple":
            pass
        elif mode == "qwen":
            res = "<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n"
            length = min(len(question), len(answer))
            # assert len(question) == len(answer)
            for i in range(length):
                res += "<|im_start|>user\n{}<|im_end|>\n".format(question[i]) + \
                       "<|im_start|>assistant\n{}<|im_end|>\n".format(answer[i])
            res = res.strip("<|im_end|>\n")
            return res
        

class BaiduBaikeFormatHandler(FormatHandler):
    """example data
    {"title": "红色食品", "summary": "红色食品是指食品为红色、橙红色或棕红色的食品。科学家认为，多吃些红色食品可预防感冒。红色食品有红柿椒、西红柿、胡萝卜、红心白薯、红果（山楂）、红苹果、草莓、红枣、老南瓜、红米、柿子等。 有治疗缺铁性贫血和缓解疲劳的作用，对乳腺癌等肿瘤疾病有防治作用，给人以兴奋感，有增加食欲，光洁皮肤，增强表皮细胞再生和防止皮肤衰老，预防感冒等作用。", "sections": [{"title": "简介", "content": "红色食品富含番茄红素、胡萝卜素、铁和部分氨基酸，是优质蛋白质、碳水化合物、膳食纤维、B族维生素和多种无机盐的重要来源，可以弥补粳米、白面中的营养缺失。经常食用红色食品，可以进一步提高对主食中营养的利用率，山植等食品还有治疗癌症的功效。被称为“红色生力军。”营养学家认为，红色蔬果最典型的优势在于它们都是富含天然铁质的食物，例如我们常吃的樱桃、大枣等都是贫血患者的天然良药，也适合女性经期失血后的滋补。所以，红色蔬果，女人尽可放心多吃。红色食品中还含有致病微生物的“杀手”——巨噬细胞，可以有效地抵御感冒病毒等微生物，增强人体抵抗感冒的能力。  红色食品\n在所有的果蔬当中，名声最好的莫过于苹果。西方有“One apple a day，keeps the doctors away．”的说法，因为苹果性情温和，含有各种维生素和微量元素，是所有的水果中最接近完美的一个。\n还有一种说法：红色食品是相对于绿色食品而言的，指对人体有害的食品，如各种有毒有害、腐败变质、添加非食用物质的食品。红色食品危害人体健康乃至生命安全，对人体健康亮起了红灯，应当大力查处。"}, {"title": "作用", "content": "这些食品中富含β-胡萝卜素和维生素A，对孩子上皮组织和呼吸道粘膜有很强的保护作用，可提高预防感冒的能力。\n假如你生来体质较弱，易受感冒病毒的困扰，或者已经被感冒缠上了，红色食品会助你一臂之力，天生具有促进人体健康卫士之一的巨噬细胞活力的功能，巨噬细胞乃是感冒病毒等致病微生物的“杀手”，其活力增强了，感冒病毒自然难以在人体内立足，更谈不上生长繁殖了。至于颜色较辣椒稍浅一些的胡萝卜，所含的胡萝卜素可在体内转化为维生素A，发挥护卫人体上皮组织如呼吸道黏膜的作用，常食之同样可以增强人体抗御感冒的能力。除了红辣椒、胡萝卜外，苋菜、洋葱、红枣、番茄、红薯、山楂、苹果、草莓、老南瓜、红米等亦具此功。"}, {"title": "红色食品与感冒", "content": "冬令时节，气候寒冷，万物收藏，人的机体生理功能处于降低、抑制、收缩状态，易患感冒，吃红色食品可扶正祛邪，增强免疫力，预防得病。[1]\n蔬菜中的红萝卜、红辣椒、番茄、红薯、红枣、红苋菜等红色食品中，富含β-胡萝卜素，不但能清除人体氧自由基，而且参与合成维生素A，对人体上皮组织和 呼吸道黏膜有很强的保护作用。推荐以下几个食疗方———\n★番茄猪肝汤\n用料：猪肝250克，虾仁25克，蘑菇40克，鸡蛋1只，番茄150克，黄酒、葱段、姜片、胡椒粉、精盐适量。\n制法：将猪肝切去筋膜洗净，切丁后加上酒、姜汁、蛋液、盐、胡椒粉，搅打成浆。用旺火蒸10—15分钟至结膏。清水加虾仁、黄酒沸煮5分钟后倒入蘑菇、番茄丁和肝膏，再煮沸，调味即可。\n功用：养肝明目，增强免疫力。用于防感冒、防治夜盲症及免疫力低下者，以及甲亢。\n方解：猪肝有养肝明目、增强免疫力；蘑菇补益脾胃，益阴养肝，降压，降脂，润燥化痰，增加白细胞；虾仁、番茄均有增强免疫力的食品，番茄可增强营养，减少感冒的发生。\n★红萝卜炖牛肉\n用料：牛肉250克、红萝卜250克。\n制法：牛肉切成小块，加黄酒、姜、葱等配料，再加入红萝卜块，炖熟，即可食用。\n功用：益气养胃、强健筋骨、增强免疫力。适用于防感冒及免疫力低、虚损消瘦、腰膝酸软者。\n方解：牛肉补脾胃、益气血、强筋骨，红萝卜增强免疫力，防感冒，健脾，补血，助消化。\n★蜂蜜红萝卜汁\n用红萝卜汁与蜂蜜各半制成混合汁剂，每天饮用3次，每次1汤匙。可防治伤风、感冒和咽喉炎。胡萝卜能提供丰富的维生素A，具有促进机体正常生长与繁殖、维护上皮组织、防止感冒及保持视力正常。蜂蜜能补中，润燥，止痛，解毒，清热。"}, {"title": "红色食品与红肉", "content": "红色食品是指外表呈红色的果蔬和“红肉”类。红色果蔬包括红辣椒、西红柿、红枣、山楂、草莓、苹果等，红色果蔬含有糖和多种维生素，尤其富含维生素C。“红肉”指牛肉、猪肉、羊肉及其制品。\n红色果蔬中的辣椒具有温中散寒，开胃除湿之功效，辣椒中的辣椒素能刺激唾液和胃肠道消化液的分泌，还能刺激心血管系统，使心跳加快，血液循环加速，因此在寒冷环境有祛风除湿的作用。风寒型感冒病人食用辣椒汤能帮助发汗，有利于感冒的康复，但是胃肠疾病、结核病人则不适合食用。西红柿-在国外享有“金苹果”之称，具有较高的价值。由于西红柿含有94%左右的水分，生吃能防治中暑，止渴生津，凉血解毒的作用，但食西红柿时尽量少放盐，为了避免维生素的破坏，做汤时最好等水开了再下西红柿，而且忌食未成熟的西红柿胃，胃肠虚寒者即慢性腹泻和消化不良者应忌食之。红枣在国外被称为“天然维生素丸”，具有很好的补血功效，能安神和补益脾胃，但胃肠积滞和患有牙齿疾病者应忌食。食用红枣时不宜与鱼同食，同食易引起腹部胀痛。\n红色食品中的肉类即所谓“红肉”，主要含蛋白质和脂肪及其它无机盐等，因此具有丰富的营养价值。不过“红肉”致癌，世界癌症研究基金会建议食用“红肉”时，每日每人撮入量应少于80克，这是因为“红肉”在烧烤、烙制、煎炸时，其表面产生多种杂环胺——致癌物。"}, {"title": "好处", "content": "红色不但能让人联想到爱情和激情，还是一种与心脏、大脑和泌尿系统的健康有关的颜色。红色的水果和蔬菜对我们的身体健康大有裨益。 红色的果蔬主要含有丰富的植物化学成分，包括抗细胞因子、抗氧化剂和番茄红素(一种产生红色的色素)。这些成分能够预防癌症，特别是肺癌、前列腺癌和消化道癌。它们还可以延缓衰老，并且有利于防止黄斑变性。黄斑变性是导致65岁以上老年人失明的主要诱因。\n1、草莓含有80%的水分、丰富的维生素C、少量膳食纤维和钾。由于含糖量很低，因此经常出现在减肥食谱中。大量抗坏血酸、凝集素和果胶使它成为降低血液中胆固醇含量的理想食物。传统医学中草莓可以作为润肤剂、净化剂和利胆剂，还具有镇咳和抗风湿的作用。人们还认为它有抗贫血和滋补的功效，可以促进机体生长。草莓叶子的浸剂还可以用于肠道消炎。\n2、每天生食6至1 2颗樱桃对痛风和尿酸过多有显著疗效。樱桃的果汁有利于治疗腹泻和结肠炎，所含的抗氧化剂具有保健作用。樱桃含有的主要养分和膳食纤维较少，但是维生素B的含量不低。在矿物质中，钾和铁的含量较高。\n3、西瓜是水分含量最高的水果，高达其总重量的95%，因此可以促进肾脏更好地发挥功能，将废物和有毒物质排出体外。\n4、覆盆子含有丰富的维生素E、多种植物营养素和不可溶性纤维。除了具有利尿和通便作用，它还可以用于治疗风湿。\n5、红苹果富含果胶、糖分和维生素C。此外，由于它是温和的通便剂，所以还具有特殊的医疗效用，可以用于治疗肠道功能紊乱。因此，自然医学认为红苹果可以抗腹泻、贫血和哮喘。它还能够缓解神经系统紧张，促进睡眠。每天晚上吃一个红苹果有助于迅速入睡。它还对希望保持体形的人有用，因为几乎不含脂肪，每100克只有不到58卡路里的热量。据法国图卢兹大学的研究结果显示，每天吃一个大苹果可以在8个星期内使胆固醇水平降低。\n6、红辣椒中抗氧化剂、硒和维生素C的含量很高，甚至高于柑桔和柠檬等酸味水果。红辣椒所含的膳食纤维能够控制血液中的胆固醇和葡萄糖，还可以改善肠道功能。\n7、红萝卜有益于治疗呼吸系统疾病，例如咽炎和喉炎，还可以减轻喉咙嘶哑。在柠檬的辅助下，它还可以用来防治哮喘和鼻窦炎。萝卜酒具有清除肾结石和治疗肝脏和胆囊疾患的作用。红萝卜含有钾和少量铁，不含脂肪，每100克只含有15卡路里的热量。它非常适于制作凉拌沙拉，配上柠檬和盐就是一道佳肴。此外，吃红萝卜还可以控制前列腺癌变。\n8、番茄含有番茄红素和大量抗氧化剂，能够降低患上慢性疾病的危险，尤其是前列腺癌和心血管疾病。番茄具有提神、助消化和抗炎的作用。用它制作的沙拉、酱汁和菜泥可以帮助患有胃炎和胃溃疡的人更好地消化不易消化吸收的食物。番茄的热量很低，含有维生素C。它富含的番茄红素可以防止罹患前列腺癌。如果使用食用油烹调番茄，还可以增强这种功效。\n"}], "tags": ["饮食", "食品", "食疗", "科学", "健康", "食品类型"], "url": "http://baike.baidu.com/view/0010.htm"}
    """
    def __init__(self, input_path, output_path, dataset_name):
        super(BaiduBaikeFormatHandler, self).__init__(input_path, output_path, dataset_name)
    
    def process_one_line(self, line, fout) -> bool:
        text = ""
        data = json.loads(line)
        title = self.zh_process(data["title"])
        content = self.zh_process(data["summary"])
        if title == "" or content == "":
            return False
        text = title + "：" + content
        for section in data["sections"]:
            text += self.zh_process(section["title"]) + "：" + self.zh_process(section["content"])
        if not self.quality_assurance(text):
            return False
        d = {"text": text}
        fout.write(json.dumps(d, ensure_ascii = False) + "\n")
        return True

class BaiduQAFormatHandler(FormatHandler):
    """example data
    {"qid": "qid_5982723620932473219", "category": "教育/科学-理工学科-地球科学", "title": "人站在地球上为什么没有头朝下的感觉 ", "desc": "", "answer": "地球上重力作用一直是指向球心的，因此\r\n只要头远离球心，人们就回感到头朝上。"}
    {"qid": "qid_5679706523376347837", "category": "娱乐-宠物", "title": "我的小baby", "desc": "我的小baby-辛巴。温顺可爱的，两个月大的小家伙，第一次养狗，该注意什么呢？求指教～[爱你]", "answer": "勤洗澡，养成好的卫生习惯"}
    特点是用户提出的问题或者回答，标点符、语法使用不够规范，并且会混入表情包，比如[爱你]。
    """
    def __init__(self, input_path, output_path, dataset_name):
        super(BaiduQAFormatHandler, self).__init__(input_path, output_path, dataset_name)
    
    def process_one_line(self, line, fout) -> bool:
        data = json.loads(line)
        title = self.zh_process(data["title"])
        answer = self.zh_process(data["answer"])
        text = self.qa2txt(title, answer, "qwen")
        
        if not self.quality_assurance(text): # todo 质量筛选
            return False
        d = {"text": text}
        fout.write(json.dumps(d, ensure_ascii = False) + "\n")
        return True

class BELLEFormatHandler(FormatHandler):
    """example data
    {"instruction": "编写一个Python函数，计算给定列表的平均值。\nnums = [3, 5, 2, 8, 10]", "input": "", "output": "可以根据以下步骤编写一个Python函数来计算给定列表的平均值：\n1. 定义函数，它将取一个列表作为参数。\n2. 计算列表中所有元素的总和。\n3. 计算列表中元素的数量。\n4. 将总和除以元素数量来计算平均值。\n5. 返回平均值作为函数输出。\n以下是Python代码实现：\n```python\ndef calculate_mean(nums):\n  total = sum(nums)\n  count = len(nums)\n  mean = total / count\n  return mean\nnums = [3, 5, 2, 8, 10]\nprint(calculate_mean(nums))\n```\n在上面的代码片段中，我们首先定义了一个叫做`calculate_mean`的函数，它将一个列表作为输入参数。然后，我们使用了Python内置的`sum`函数来计算列表中所有元素的总和，使用`len`函数计算列表中元素的数量，然后将总和除以元素数量来计算平均值。最后，我们使用`return`语句将平均值作为函数输出。\n代码中的下一行创建一个名为`nums`的变量，其中包含我们要计算平均值的数字列表。最后，我们使用`print`函数输出函数的结果，即给定列表的平均值，结果为`5.6`。"}
    """
    def __init__(self, input_path, output_path, dataset_name):
        super(BELLEFormatHandler, self).__init__(input_path, output_path, dataset_name)

    def process_one_line(self, line, fout) -> bool:
        data = json.loads(line)
        if "instruction" not in data:
            return False
        instruction = self.zh_process(data["instruction"])
        output = self.zh_process(data["output"])
        text = instruction + "\n" + output # todo: 更好的连接词？
        if not self.quality_assurance(text):
            return False
        d = {"text": text}
        fout.write(json.dumps(d, ensure_ascii = False) + "\n")
        return True

class BELLEConversationsFormatHandler(FormatHandler):
    """example data
    {"conversations": [{"from": "human", "value": "针对健身房的新手，设计一套适合
他们的健身器械使用指南，包括安全应用、正确姿势等方面。"}, {"from": "assistant", "value": "健身器械使用指南\n1. 开始前，请先进行热身运动。这会帮助你的身体>适应运动，并减少受伤的风险。\n2. 在使用健身器械前，确保你已经了解了其使用方法
。请阅读说明书或咨询教练以获得正确的使用技巧。\n3. 谨防过度使用或过度挑战你的
身体。 如果你觉得有些动作太难或太重，请添加锻炼计划，以逐步提高动作难度。\n4. 使用合适的装备。 确保你拥有合适的运动鞋和舒适的运动服。 不要在裸露的脚或短裤
上进行重量训练。\n5. 在健身器械上使用安全装置。 这些通常用于保护你的身体免受>不当操作造成的损伤。 例如，重量训练中，你需要使用杠铃和负重时，一定要使用卡子
来防止重量滑落。\n6. 注意正确的姿势。 如果你的姿势是错误的，那么你的身体很容>易被伤害到，你也可能无法获得最佳的锻炼效果。 至关重要的是，保持直立的身体，保
持头部和颈部的稳定，并使用合适的重量。\n7. 保持合理的呼吸方式。 无论何时进行>训练，都必须保持正常呼吸。 当你需要用力时，呼气； 当你放松时，吸气。\n8. 安全
存放器械。 在使用健身器械后，你需要把它们归还给适当的位置，以便其他人可以使用
它们。\n总之，健身器械的正确使用是关键之一，如果不健康和不安全，它们将无法帮>助您达到您所需的健康成果。 选择适当的训练计划，并为训练提供足够的时间，以备逐
渐适应新方法。 对于任何问题，请向教练咨询。"}], "id": "66182880"}
    """
    def __init__(self, input_path, output_path, dataset_name):
        super(BELLEConversationsFormatHandler, self).__init__(input_path, output_path, dataset_name)

    def process_one_line(self, line, fout) -> bool:
        text_list = []
        # text_list.append("以下是一些对话：")
        data = json.loads(line)
        if "conversations" not in data:
            return False
        conversations = data["conversations"]
        temp_pair = ""
        q_list = []
        a_list = []
        for index, item in enumerate(conversations):
            if index % 2 == 0 and item["from"] == "human":
                q_list.append(self.zh_process(item["value"]))
            elif index % 2 == 1 and item["from"] == "assistant":
                a_list.append(self.zh_process(item["value"]))
        text = self.multi_qa2txt(q_list, a_list)
        if not self.quality_assurance(text):
            return False
        d = {"text": text}
        fout.write(json.dumps(d, ensure_ascii = False) + "\n")
        return True
    
class FireflyFormatHandler(FormatHandler):
    """example data
    {"kind": "NLI", "input": "自然语言推理：\n前提：他觉得自己已离开了很久的时间,而这里的人和事竟然依旧,似乎是在等着他归队,真叫人倍感温馨\n假设：他是个酒吧老板。\n两者是什么关系？", "target": "中立"}
    {"kind": "NER", "input": "下文中存在哪些实体：\n如今两国又进行耗资巨大的核军备竞赛，这势必严重影响本国经济发展和人民生活改善。", "target": "不存在实体"}
    {"kind": "Summary", "input": "在上海的苹果代工厂，较低的基本工资让工人们形成了“软强制”的加班默契。加班能多拿两三千，“自愿”加班成为常态。律师提示，加班后虽能获得一时不错的报酬，但过重的工作负荷会透支身体，可能对今后劳动权利造成不利影响。\n输出摘要：", "target": "苹果代工厂员工调查：为何争着“自愿”加班"}
    {"kind": "Cot", "input": "请一步一步认真地思考下面的问题：\nFran is in charge of counting votes for the book club's next book, but she always cheats so her favorite gets picked. Originally, there were 10 votes for Game of Thrones, 12 votes for Twilight, and 20 votes for The Art of the Deal. Fran throws away 80% of the votes for The Art of the Deal and half the votes for Twilight. What percentage of the altered votes were for Game of Thrones?", "target": "First find the total number of The Art of the Deal votes Fran throws away: 80% * 20 votes = 16 votes. Then subtract these votes from the total number of The Art of the Deal votes to find the altered number: 20 votes - 16 votes = 4 votes. Then divide the total number Twilight votes by 2 to find the altered number of votes: 12 votes / 2 = 6 votes. Then add the altered number of votes for each book to find the total altered number of votes: 6 votes + 4 votes + 10 votes = 20 votes. Then divide the number of votes for Game of Thrones by the total altered number of votes and multiply by 100% to express the answer as a percentage: 10 votes / 20 votes * 100% = 50%.\n因此，最终的答案是：\n50"}
    {"kind": "Couplet", "input": "根据上联给出下联：风阅大江头，风流何处？江流何处", "target": "下联：人浮沧海外，人在天涯，海在天涯"}
    """
    def __init__(self, input_path, output_path, dataset_name):
        super(FireflyFormatHandler, self).__init__(input_path, output_path, dataset_name)

    def process_one_line(self, line, fout) -> bool:
        data = json.loads(line)
        kind = self.zh_process(data["kind"])
        input_str = self.zh_process(data["input"])
        target_str = self.zh_process(data["target"])
        # text = "\n".join(["任务类型：",kind, "问题：", input_str, "回答：", target_str])  # todo，更好的连接词？
        text = self.qa2txt(input_str, target_str, "qwen")

        if not self.quality_assurance(text):
            return False
        d = {"text": text}
        fout.write(json.dumps(d, ensure_ascii = False) + "\n")
        return True

class MossFormatHandler(FormatHandler):
    """example data
    {"conversation_id": 1, "category": "Brainstorming", "conversation": [{"human": "如何保障工作中遵循正确的安全准则？", "assistant": "为了保障工作中遵循正确的安全准则，以下是一些建议：\n\n1.了解相关安全规定和标准：了解相关的安全规定和标准，并遵守它们。这可以包括公司和政府的安全标准，以及行业标准和最佳实践。\n\n2.培训和教育：确保您和您的同事接受了必要的培训和教育，以了解正确的安全准则和行为。\n\n3.使用正确的工具和设备：确保您使用正确的工具和设备，并且它们得到了正确的维护和保养。\n\n4.个人防护装备：确保您和您的同事穿戴正确的个人防护装备，如安全鞋、透明眼镜或面罩、手套等。\n\n5.创建一个安全文化：鼓励个人对安全的责任感和意识，并创建一个安全文化，使人们始终关注他们自己和他人的安全。\n\n6.持续监测和改进：持续监测和改进安全准则和程序，以确保它们保持最新，并适应变化的情况。\n\n这些措施可以帮助您和您的同事在工作中保障正确的安全准则，确保您的工作场所是一个安全的环境。"}, {"human": "如何应对突发紧急情况？", "assistant": "突发紧急情况可能会在任何时间发生，为了应对这些情况，以下是一些建议：\n\n1.保持冷静：保持冷静和清醒，以便能够更好地应对情况。\n\n2.评估情况：评估紧急情况的性质和范围，以便了解应该采取哪些行动。\n\n3.触发应急计划：如果您的机构或公司有应急计划，立即触发它，并按照计划的步骤行动。\n\n4.联系相关人员：通知必要的人员，例如紧急服务、管理层或其他相关人员，并与他们保持联系。\n\n5.遵循安全准则：在处理紧急情况时，请遵循正确的安全准则，确保自己和其他人的安全。\n\n6.提供及时信息：尽快向相关人员提供准确的信息，以便他们能够做出正确的决策。\n\n7.合作应对：与其他人合作应对紧急情况并相互支持。\n\n总之，应对突发紧急情况需要保持冷静和清醒，评估情况并采取适当的行动。同时，需要遵循正确的安全准则，并与其他人合作应对紧急情况。"}, {"human": "在网络安全方面，如何避免遭受黑客攻击？", "assistant": "以下是一些避免遭受黑客攻击的建议：\n\n1.更新安全软件：确保您的操作系统、应用程序和安全软件是最新的，并随时更新它们。这可以帮助您及时发现和修复安全漏洞。\n\n2.使用强密码：使用强密码，包括字母、数字和特殊字符。不要使用容易猜测的密码，如生日、姓名或常用单词。\n\n3.使用多因素身份验证：使用多因素身份验证来增加账户的安全性，例如发送短信验证码或使用指纹识别。\n\n4.小心附件和链接：不要打开未知的附件或链接，因为它们可能包含恶意软件。\n\n5.备份重要文件：定期备份重要文件，并将其存储在安全的位置。\n\n6.保护个人信息：不要在互联网上公开个人信息，例如出生日期、地址或社交安全号码。\n\n7.使用加密连接：在访问敏感信息时，使用加密连接，如HTTPS。\n\n8.教育员工：向员工提供网络安全培训，并确保他们了解正确的安全措施和行为。\n\n总之，避免遭受黑客攻击需要采取多种措施，包括更新安全软件、使用强密码、使用多因素身份验证、小心附件和链接、备份重要文件、保护个人信息、使用加密连接以及教育员工。这些措施可以帮助您保护个人信息和数据免受黑客攻击。"}]}
    基于MOSS-002内测阶段采集的约10万用户输入数据和gpt-3.5-turbo构造而成，相比moss-002-sft-data，moss-003-sft-data更加符合真实用户意图分布，包含更细粒度的有用性类别标记、更广泛的无害性数据和更长对话轮数，约含110万条对话数据。
    """
    def __init__(self, input_path, output_path, dataset_name):
        super(MossFormatHandler, self).__init__(input_path, output_path, dataset_name)

    def process_one_line(self, line, fout) -> bool:
        """语言本身质量较高"""
        data = json.loads(line)
        text_list = []
        category = data["category"]
        conversation = data["conversation"]
        q_list = []
        a_list = []
        for temp in conversation:
            q_list.append(self.zh_process(temp["human"]))
            a_list.append(self.zh_process(temp["assistant"]))
        text = self.multi_qa2txt(q_list, a_list)
        # text_list.append("以下是一组任务类型为{}并且话题相关的对话：".format(category))
        # for temp in conversation:
        #     q = self.zh_process(temp["human"])
        #     a = self.zh_process(temp["assistant"])
        #     text_list.append("问题：\n{}\n回答：{}".format(q, a))
        # text = "\n".join(text_list)
        if not self.quality_assurance(text):
            return False
        d = {"text": text}
        fout.write(json.dumps(d, ensure_ascii = False) + "\n")
        return True
                    
class WikiCNFormatHandler(FormatHandler):
    """example data
    [
        {
            "completion": "昭通机场（ZPZT）是位于中国云南昭通的民用机场，始\",
            "source": "wikipedia.zh2307"
        },
        {
            "completion": "佐洛奇夫（Zolochiv），或按俄语译为佐洛乔夫（Золочев），是乌克兰西部利沃夫州佐洛奇夫区Золочівська міська громада内的城市，为该区及该市镇的行政中心。",
            "source": "wikipedia.zh2307"
        }
    ]
    """
    def __init__(self, input_path, output_path, dataset_name):
        super(WikiCNFormatHandler, self).__init__(input_path, output_path, dataset_name)
    
    def process_one_file(self, file_path):
        line_count = 0
        jump_count = 0
        with open(self.output_path, "a") as fout:
            with open(self.input_path + "/" + file_path, "r", encoding="utf-8") as fin:
                data = json.load(fin)
                for item in data:
                    line_count += 1
                    if not self.quality_assurance(self.zh_process(item["completion"])):
                        jump_count += 1
                        continue
                    d = {"text": self.zh_process(item["completion"])}
                    fout.write(json.dumps(d, ensure_ascii = False) + "\n")
        return line_count, jump_count

class ZhihuFormatHandler(FormatHandler):
    """example data
    column: INSTRUCTION, RESPONSE, SOURCE, METADATA
    INSTRUCTION:
        ['怎么说服男朋友买烤箱？',
        '航天从业者是如何看待电视剧《你是我的荣耀》的？',
        '如何看待PayPal正式进入中国？',
        '中金公司交易员月薪八万五是如何做到的？',
        '摇滚乐（金属）给你们带来了什么？',
        '有没有跟我一样的朋友在这个二十多岁的就得了肺结核咯血啊？',
        '如何看待西南石油大学食堂学生外出不便基本只能在校内用餐导致食堂大规模出现患胃肠炎教工黑人留学随意进出？',
        '如何看待警方通报「南师大学生宿舍猝死」事件调查结果：「排除他杀」？',
        '美国宣布核聚变重大突破，首次实现 「核聚变点火」，有哪些重大意义？距离真正的商业化还有多远？',
        '如何看待华为诺亚方舟实验室在微软MIND新闻推荐比赛中的疑似作弊事件？']
    RESPONSE:
        ['emmmmm，首先想说的是，我买厨房用品一般是不用「说服」的，只是在厨房堆的满满当当的情况下会象征性的问一下我老公，他就会回答我说：你看看你还有地方放吗。然后我会思考一下，如果是特别想买的，就不会问他了。自己决定就好。 比如，前几天我又买了两个盘子~~~~他还不知道。 可以给题主看看我有多少的锅具：自家炒菜用什么锅好？各有什么优缺点？ 说回烤箱的问题，买的时候处于热恋期，我告诉他我有一个买烤箱的计划。虽然他基本不吃点心，也不喜欢烘焙，但那个时期的他欣然同意并热情洋溢的给我选烤箱。可能是他有憧憬我会给他做什么好吃的吧。又因为我是一个不怎么吃甜食的湖南人，烤箱在我家烘焙的使用率很低。 但是！！你还是可以告诉他烤箱的作用是可以烤制各种肉类！！！我不相信有不喜欢吃肉的男生！！烤箱真的是可以烤一切的肉类，熟悉之后会觉得非常简单。 我很久以前用烤箱做的最多的就是烤羊排和烤鸡翅，我老公不怎么吃羊肉和鸡翅。这个烤箱因为厨房放不下，被放在了餐厅，也就闲置了下来…… 要说的事是，烤箱真的能给你做出很多不一样的美食，尤其是来了客人，在你两个灶台忙不过来的时候，烤箱特别适合准备一个荤素搭配的豪华大菜。在烹饪其他需要爆炒的菜肴的空档去处理一下就可以了。  总结来说理由如下： 1、如果你家是你做饭多，那么为什么有这么多话说， 也不是他用，等着吃就好了。 2、工欲善其事，必先利其器。没有好的工具怎么能吃到更好的美食。 3、我要我喜欢，不要你喜欢。我还不能有个爱好吗？',
        '  难得有个关于航天的剧，职场情节悬不悬浮，航天设定和细节走不走心？带着放大镜看了前18集，还蛮惊喜的。这剧的细节很丰富，男主的成长线也设置得很讲究，有点意思。 这两周一直和哈工大紫丁香卫星的小伙伴们一起讨论剧情，发现可说的点真的相当多。 以下主要盘点解析的是前10集剧情，必要的地方也会涉及一些后面的集数。 （去年就带放大镜看过《恋爱小行星》：看木星、认石头、还要寻找小行星？这波柔软又硬核的安利我吃了！，感兴趣的可以回顾一下~）   仔细抠一抠这剧的时间线，会发现男主于途的成长经历，与我国的航天进程高度相关。 虽然剧里明显有隐去故事发生年份的意思，但这对灰原童鞋我，新时代的列文虎克，完全不是问题！ 第一集乔晶晶回忆高中加于途QQ的剧情里，里可以看到于途属马，大概率是1990年出生。  于途说自己“人到三十”，也就是说剧里现在的时间大约是2020年。  那这个30岁会不会是虚指呢（比如31、32岁啥的）？不是的，我们可以通过乔晶晶的生日来double check。第一集可以看到，乔晶晶也属马，生日是1990年12月21日。  第七集里乔晶晶说自己现在才29，下个月才30岁生日。说明到第七集这个时间节点是2020年11月，于途确实是30岁零2个月。  再考虑到这时候乔晶晶和高中同学于途重逢不到一个月，所以第一集应该发生在2020年10月底到11月初左右。 后续剧情也有细节能对的上：第8集，能看出是2020年11月的日历 （这说明：这剧细节还是经得起推敲的于途和乔晶晶都是实诚人，QQ信息居然都用的是真实生日） 明确真实的时间节点，让于途这个从小热爱航天科学的角色形象有了更充分的铺垫。  于途高中时候（直到现在）的QQ昵称和论坛id都叫“玉兔捣药”▼  “玉兔”一方面是“于途”这个名字的谐音，另一方面也是他对月球探测感兴趣的体现。第二集的高中回忆里同学说“探索月球是于途的梦想”▼  这里提到的嫦娥一号，是我国首个月球探测器。发射于2007年10月24日，那时候于途17岁高二或者高三，年龄对的上。  高中时候的于途显然对嫦娥一号做了不少功课。第一集里乔晶晶搜索于途的论坛帖子，查到的也是他关于嫦娥一号的发帖：《我们的征途是星辰大海——关于嫦娥一号已经出发，我们离登陆月球还有多远》▼  帖子里除了介绍嫦娥一号的基本信息和探测目标，还整理了嫦娥一号的轨道信息▼  值得一提的是，仔细看帖子里，除了提到了月球探测器们都会经历的“地月转移轨道”之外，于途还专门介绍了嫦娥系列里只有嫦娥一号用了的调相轨道（phasing orbit），可以说是小小年纪就是资深爱好者了~  后续剧情里，于途和嫦娥任务的缘分也不浅。按前面这个时间线继续推，那他就是08或者09年大一，本硕博9年（学霸嘛），17或者18年左右博士毕业。在嫦娥一号之后的十年里，于途的学生生涯也伴随着嫦娥二号和嫦娥三号任务的推进和结束任务。（详见：月球探测六十年【行星事务所2020年版】）  高中时候的于途发帖探讨“我们离登陆月球还有多远”，而在他博士还没毕业的时候，我国的嫦娥三号就已经带着月球车玉兔号实现了登陆月球。   于途在高中之后也一直很关注嫦娥任务。 第七集里可以看到，于途家里（至少）有两个月球车的模型（我好酸）。书桌上这个罩子里的看不清楚细节：  书柜上这个给了特写的是玉兔二号月球车的模型：  注意，是嫦娥四号携带的玉兔二号，不是嫦娥三号携带的玉兔号。这俩虽然很像，但玉兔号前面是有机械臂的，兔二没有。  这个细节是符合剧里的时间背景的：嫦娥四号和玉兔二号是2018年发射，2019年初着陆月球的（详情介绍：嫦娥四号发射成功：去往从未踏足过的地方，需要一点勇气和兔二醒来，两器互拍！真正的探险才刚刚开始！），到2020年11月这个时间节点，家里有玉兔二号的模型很合理。  第七集乔晶晶安慰和鼓励于途说：你已经是看过最多星星的一只兔子了。 于途立刻就能反应过来这句来自玉兔号的微博。  事实上，这句话确实出自2016年@月球车玉兔 发的最后一条微博。那时候玉兔号因为故障已经不能再继续工作了，所以和大家告别“这次真的晚安咯！还有好多问题想知道答案…但我已经是看过最多星星的一只兔子了！”  能对四年前的一条微博记忆如此深刻和准确，于途当年估计没少关注嫦娥三号和玉兔号。    正如剧里多次提到的：航天是个系统工程。把一颗卫星（探测器）送上天，守护它们的正常运行，顺利接收它们的探测数据，需要不同领域的工程师和科学家们参与协作。   但如果想要大致分个类的话，“搞航天的”可以分成：造火箭的、做卫星（探测器）的和搞联络的。 那于途具体是干哪个的呢？  1）造火箭的（×） 提到“航天”，最容易想到的可能就是造火箭。  火箭，是把卫星（探测器）送往预定轨道的交通工具。剧里主持人提到的这个“胖五”——长征五号火箭，就是我国目前尺寸最大，运力最强的火箭，能把8吨重的嫦娥五号送往月球，把5吨重的天问一号送往火星。国家队之外，我们熟知的商业航天公司：美国的SpaceX、蓝色起源，国内的蓝箭航天，很大一部分业务也是造火箭。  2）做卫星（探测器）的（✔） 不过，于途不是造交通工具的，他负责照顾的是交通工具搭载的“乘客”，也就是卫星（探测器）。 卫星这东西说起来好像很遥远，但其实早已和我们的日常生活息息相关。 个人很喜欢剧里第一集的几个场景，气象卫星、导航卫星、通讯卫星一一闪过，与之对应的是地球上的我们通过分析这些卫星的数据，知道“今天交通有点堵、外面要降温”。 除了这些围绕地球运转，观测地球的卫星之外，同样也有观测月球、火星，甚至更遥远星球的卫星（探测器），后者都属于“深空探测”。我们前面说到的嫦娥n号、玉兔n号，都属于深空探测，于途就是做这个的。  还记得第一集里于途汇报的那个项目吗？标题叫《SK-1探测器方案设计报告》，SK应该是“深空”的缩写。（emmm那要是通过了，以后这个项目的二号叫啥？SK-？）  从事“深空探测”这个设定，也完全符合第2集里，高中于途说将来要“超越月球征服火星飞出太阳系”的目标。从少年时的梦想，到如今为之奋斗的事业，对这个角色来说，可以算是一以贯之的热爱了。  当然，即使是细化到照顾某颗卫星，这依然是一个极其复杂的系统工程，光是演员表里就有这么多相关工种。  而于途和关队关在所在的“总体部”，可以简单理解为一个协调各部门的“总管家”。  不过，从剧情来看，于途实际负责的卫星并不止深空探测卫星，接下来的JX-1卫星，就是一颗不折不扣的地球探测卫星。 剧里说这颗在轨一年多的卫星，是于途来到航天所之后接手的第一颗型号，按于途2017年左右博士毕业来算，到剧里开场在航天所工作了2-3年，时间也对得上。  3）搞联络的（×） 不管是火箭还是卫星（探测器），从它们离开地球表面，到结束工作，都需要和地面站保持通讯——尽管存在感最低，民众所知也最少，但负责联络卫星和地面站的通讯工作至关重要，测控工程师是每颗卫星背后的守护者。  “牧星人”正是人们对测控工程师的爱称▼  作为负责卫星的总体部工程师，于途虽然自己不搞通讯，但也需要具备一定的通讯知识，并在遇到问题的时候与负责通讯的专业人员共同协作解决问题。接下来拯救卫星的重头戏里出场的西北测控中心，原型就是我国的西安卫星测控中心，这里的工程师们，就是专门负责卫星联络工作的。  前十集里认真搞事业的第一个案件，是第9-10集前往西北测控中心抢救卫星JX-1。名字有点拗口，后面我们就叫它“加薪一号”吧，让它成为打工人的幸运星~  这段剧情还是很动人的：一群不同部门的工程师，为抢救一颗遥远卫星，协同战斗，通宵连轴转查找故障，尝试各种解决方案，最终成功把卫星从死亡边缘拉了回来——即使是不了解航天的观众，想必也能感受到几分个中艰辛和喜悦。  想知道加薪一号（JX-1）卫星到底出了啥故障，没有航天基础的观众们可能需要先了解几个基本概念。 1）遥测 一颗健康的卫星在天上工作的时候，需要时不时把自己的工作情况发送给地面站。这些“工作情况”传回地球就叫“遥测信号”，包括自己运行的位移、速度、加速度、姿态、各组件是否正常工作等等。通过分析和解译这些卫星发回遥测信号，地面站的工作人员就可以保持对卫星的跟踪，了解卫星的位置和健康状况；如果卫星发生了故障，航天工作者们也需要借助遥测数据做诊断和“治疗”。 不仅是卫星（探测器），火箭发射之后也需要传回遥测信号。例如我们看发射新闻时提到发射嫦娥五号的是“长征五号遥五”，这里的“遥”也是“遥测”的意思。  2）指令 天上的卫星向地上发送遥测信号，而地上的测控站也需要向卫星发送指令信号，控制和指挥卫星的工作。 剧里这段翻译一下，就是加薪一号（JX-1）在飞过我国地面测控站范围的时候，地面站没收到卫星的“例行健康报告”，地面站主动联络了卫星，让卫星换个应答机试试，但还是没收到报告——卫星失联了。  3）下行 除了遥测信号，卫星还会向地面站传回自己的科学探测数据，这些天上的卫星传回地面站的信号，统称为“下行”信号。反之，地面站向卫星发送的指令和数据就是“上行信号”。  这段换了个人对话，其实意思差不多：地面站给卫星发了消息，但卫星没有回复。  但可能导致失联的原因可太多了，航天是个系统工程，任何一个部件或者环节出了问题都可能导致失联，所以找故障原因，可能是个耗时耗力的持久战。 收发信号的仪器不回复，可能是这个仪器坏了，可能是电源坏了，也可能是卫星轨道偏了…  逐项排除：电源没问题，轨道也没问题。  经过各种排查之后，剧里最终锁定的问题是卫星受到了高能粒子的影响，发生了“单粒子翻转”。  高能粒子是空间物理学范畴，所以剧中要紧急联系中科院空间所（原型为中科院国家空间科学中心）的科学家们共同参与调研和营救。 “单粒子翻转”（Single-event upset，SEU）指的是单个高能粒子作用于卫星的电子器件，引起器件的逻辑状态变化。但这种作用本身一般并不会造成硬件上的损坏，处理得当是可恢复的 [1]。   卫星在运行过程中受到高能粒子的影响，这是确实会发生的，而且在无防护的状态下并不算“小概率”。同时影响主备机才是小概率 。  太阳风暴中发生的耀斑和日冕物质抛射（CME）都可能产生高能粒子。  天体磁场产生的辐射带（例如地球的范·艾伦辐射带）中，还有各种宇宙射线中，也会带来高能粒子。 事实上，许多卫星都会受到单粒子效应（单粒子翻转是其中一种）的影响，只是不一定会严重到造成仪器故障。即使是引起器件故障的单粒子事件，在上个世纪也不算罕见。在《空间天气及其物理原理》[2] 这本书里，介绍了1982-2003年之间的几次典型的单粒子事件引起的故障，可以看到，这样的事件发生率并不低，并不是十一年这么久才会发生一次。   具体到剧中的加薪一号（JX-1），故障设定的原型可能是我国的第一颗极地轨道气象卫星——风云一号A星。1988年，这颗卫星因为单粒子翻转事件导致姿态失控，结束任务。  所以严格来说，这个故障设定是有些“穿越”的。因为如今的卫星在设计的时候都会考虑到高能粒子的影响，再加上冗余备份，这类上个世纪可能遇到的严重故障，在2020年已经很少发生了，至少不会毫无准备抓破脑袋想半天才想到这个故障原因了。 但剧中作为一个模糊年代背景的案例，也算是一种来自未来的致敬吧。而且整个抢救过程还是相当专业、跌宕起伏且有代入感的。 接下来，明确了问题就好办了。按照剧情设置，加薪一号（JX-1）的应答机只是被高能粒子打懵了，其实并没有坏掉。so，万能大法，重启试试。 重启应答机之后，通讯恢复，地面站顺利收到了卫星当下的健康报告（遥测信号）。  但通过分析卫星的报告，大家又发现了两个新问题：（1）卫星不能控制飞行姿态，导致太阳能板不能对准太阳充电；（2）卫星耗电过大，这样下去会没电。  找到了问题，就能对症下药：（1）耗电大就节能省电，（2）不能充电就尽快校正姿态，让太阳能帆板恢复对日充电。  这次方案是对的，但实际没有成功，卫星传回的遥测信息显示，它没能完成地面站的指令。 这次是因为控制姿态和轨道（姿轨控）的主份控制器也坏了。  最后，切换姿轨控的备份机再试，卫星终终终于成功对日定向，充上电了。  满血之后恢复正常工作。  抢救流程大体上是这样的：  总之，除了故障原因的设定上有点“穿越”和强行巧合之外，整个救援过程的设置总体上是专业且合理的。航天技术顾问没白找，剧组真的有认真采纳专业的航天指导~  除了这些之外，剧里各种跟航天有关的场景和细节也都挺用心的。 于途和关在工作的中国宇航研究院上海空间科学研究所，原型是航天八院 [3]，也就是中国航天科技集团有限公司三大总体院之一的上海航天技术研究院。  相关场景是在航天八院805所实景拍摄的▼  第1集里于途路过的火箭模型和投影，从左到右分别是航天八院研制的长征二号丁（CD-2D）、长征四号乙/丙（CZ-4B/4C)、2个长征六号（CZ-6）、长征六号甲（CZ-6A）和长征六号X（CZ-6X）： 八院展厅实拍▼  第8集于途给同事发的关于气凝胶的论文资料，至少有一部分是真实存在的（还有一些可能我没查到）▼  第9集的控制大厅有模有样，虽然工作人员没戴帽子也没怎么秃，但最后排的茶杯抓到了灵魂▼  制定抢救计划之后，向卫星发指令的是位于我国东北部的佳木斯测控站▼  但随着卫星的飞行和地球的自转，下一次最适合与卫星联络的就变成了昆明测控站。之后又反复切换昆明站和佳木斯站▼  我国目前有多个测控站，分布在国内外各地。世界各国的航天机构也都是这样，通过不同位置的测控站接力完成对卫星的测控跟踪。（之前介绍隼鸟2号的测控时也讲过这种“接力测控”：JAXA隼鸟2号将于2月开展第一次着陆采样）   还是第9集，关在随口一句台词“胡所在太原出差”也是有用心设计的。我国四大发射中心：酒泉、太原、西昌、文昌，胡所去太原发射中心出差非常合理。（当然，众所周知（？），“XX发射中心”也不一定在XX地，只是这么叫了）  剧中出现的两位老一代航天人“张致学”“胡敬森”，名字合起来是“致敬钱学森”的意思▼  甚至于途的手机微信群名也有精心设计，他的工作群叫“今天你归零了吗”。“归零”指的是航天任务遇到一些难以解决的故障时要从零开始检查，直至完全解决。这个词既是航天人的噩梦，也是航天人对待任务认真的态度和严格的自我要求。  当然，bug也是有的。 比如第一集乔晶晶回忆2007年查看的这个“星系天文学论坛”，页面显然脱胎于真实存在的“航空航天港”论坛，但里面帖子的内容很多都不是07年可能看到的。阿尔忒弥斯3号，高分十三号，联盟MS-18载人飞船，凤凰号发现火星上存在水的证据，板块里还有“商业航天”板块……一个2007年的论坛页面里有多少穿越元素，仔细找找也还挺有趣的~   第8集里，发资料就发资料，发送快捷方式是什么鬼啊（据观众反馈，这部分鹅已经修改了~）  第9集里，卫星姿轨控异常时，也不会缩起太阳能板的。太阳能板通常展开了就缩不回去了▼  不过，瑕不掩瑜，目前的剧情科学性整体还是不错的~  以上就是1-10集全部航天剧情解读啦，下面几集的重头戏是巡视器XS-2的测试…我们下期（可能）继续哦~    对了插播一下，对航天感兴趣的朋友们，推荐下我的新书《向太空进发·星球探测系列》。这是目前唯一一套系统介绍我国探月、探火、探测小行星进展的科普绘本，探月中心、人民日报、吴伟仁院士推荐过的~适合3-100岁小盆友～   教练，研究火星，我还有机会么？| 行星事务所特辑 看木星、认石头、还要寻找小行星？这波柔软又硬核的安利我吃了！  感谢紫丁香卫星团队、小海、尞祡对本文提升所做的帮助~  [1] Single Event Effects | https://radhome.gsfc.nasa.gov/radhome/see.htm [2] 德洛丝·尼普. 空间天气及其物理原理. 科学出版社, 2010 [3] 八院简介 | http://www.sast.spacechina.com/n1323876/n1323907/index.html [4] 吴伟仁, 李海涛, 李赞, 等. 中国深空测控网现状与展望. 中国科学: 信息科学, 2020, 50: 87–108, doi: 10.1360/ SSI-2019-0242 ',
        'PayPal不仅是美国支付巨头，也是国际支付巨头，目前已开拓全球200多个市场，美国以外的市场贡献了43%的交易量和54%的净收入（2018年数据）。 国内的支付机构差不多长一个样，PayPal显然与之不同，国际化程度更是让国内支付机构望尘莫及。正因为这样，PayPal入华才会给人想象空间。问题是，外来的和尚能念好国内的经吗？ 很多人认识PayPal，是从支付宝开始的。市场普遍认为，支付宝与PayPal之间，有一段青出于蓝的故事。 PayPal成立于1998年，2002年被ebay并购，成为ebay买卖双方的交易工具；2003年，淘宝上线支付宝，为买卖双方提供担保交易。从先后次序看，支付宝的灵感来自于PayPal。 最初的几年，支付宝与PayPal就像两条平行线，在不同的市场做着相似的事情，如从支付工具演变成支付钱包，再衍生出信用支付（贷款）产品。2014年，二者开始在战略层面出现重大差异——这一年，蚂蚁金服成立，全面转向综合性金融服务集团；而PayPal则酝酿与ebay拆分，谋求独立上市。 之后的一年里，两者分别完成了各自的大动作，支付宝再次战略升级，从金融服务平台转型转型生活服务平台；PayPal则如愿上市，开始在华尔街的指挥棒下为规模和营收奔跑。 三年后，二者已决然不同。支付宝变身一站式生活服务平台，而PayPal仍是一家支付机构，支付营收贡献占比高达89%。 那么，仅就支付业务本身来看，PayPal的表现究竟如何呢？ （1）交易规模 PayPal是国际支付巨头，但与国内支付机构比规模，也只是二线水平。2018年，PayPal在全球共计实现交易量5087亿美元（不含网关支付），折合人民币4万亿元，放在中国市场（2018年国内非银行支付交易规模208万亿元），占比不足2%。 从增长趋势看，2013年以来，PayPal交易规模年均增速在20%-30%之间，与同期国内支付机构动辄上百的增速比，只能说差强人意。 （2）盈利能力 交易规模虽不占优势，但PayPal的盈利能力绝对羡煞旁人。2018年，PayPal实现净利润20.57亿美元，折合人民币141亿元。相比之下，国内支付机构困于盈利难的僵局，不得不为三斗米折腰，个别机构甚至不惜铤而走险，违规经营以至罚单不断。即便是几个巨头，也是通过“贷款补贴支付”实现商业层面的可持续性。 PayPal的盈利，取决于其远高于国内同业的收费标准。以美元入账为例，PayPal的支付费率一般在交易额3.4%以上（视商家交易额差异化定价，最高可升至4.4%），且需支付0.3美元/笔的固定费用。若涉及货币兑换，PayPal还要单独收取货币兑换费。而PayPal自身的支付成本费率基本在1%以下，意味着支付交易的毛利空间至少在2.4个百分点以上，扣除其他运营成本，仍然有较大的盈利空间。 从这个角度看，PayPal高盈利并无什么秘密武器，纯粹是低竞争下的高定价所致。一旦深度涉足中国市场，一样会陷入盈利难困境。反过来讲，国内支付机构争相走出去，看中的也是国际市场更高的毛利空间。 PayPal是一家立足欧美、交易规模中等、盈利能力强、国际化程度高的支付机构，人蓄无害，国内支付机构只有发力海外时才会视之为竞争对手。但随着PayPal收购国付宝70%的股权，人们开始关心，PayPal进来后能为中国支付市场带来什么改变？ 从业务资质看，国付宝持有互联网支付、移动支付、基金支付、跨境人民币支付以及预付费卡发行与受理等支付牌照和业务许可，缺失了收单牌照，意味着PayPal很难在线下市场与国内支付巨头一较高下，战场仍在线上。 线上支付，很大程度上取决于线上场景，而国内大的线上交易场景基本均已布局支付牌照，PayPal的腾挪空间非常有限。 一则缺乏C端用户基础。国付宝没有C端基础，PayPal虽有2.67亿年度活跃用户，在中国市场却没什么积累。一个缺乏C端用户的支付机构，对交易场景方而言，只会额外增加消费者负担（新增绑卡及实名认证等环节），降低交易成功率，合作积极性自然不大。 二则大规模拓客空间不再。没有用户，可以营销获客。但看看中国中小支付机构的生存现状，就知道C端获客有多难、成本有多高。此外，PayPal面临的是C端用户和B端商户的双边获客问题，这两类客户均习惯了国内的补贴打法，习惯了高毛利的PayPal是否愿意走上补贴之路呢？即便做出这个艰难的决定，作为一家独立上市公司，是否有魄力在中国市场投入百亿资金来打赢这场战争呢？大概率是不可能的。 所以，放眼未来三五年，PayPal在国内市场的突破口只有一个：跨境支付。以此为突破口，积累C端用户、累计B端商户，三五年后视市场和政策变化再做打算。 说到跨境支付，PayPal还是底气十足的。 一方面，国际化是PayPal的差异化优势。PayPal支付平台遍及全球200多个国家和地区，支持100多种货币支付和56种货币提现操作。 另一方面，跨境贸易支付一直是PayPal国际化布局的重要抓手。近年来，跨境贸易支付一直为PayPal稳定贡献着约20%的交易量。 PayPal对跨境贸易支付的倚重，固然有跨境支付高费率的考虑，更多地还是受限于牌照限制。支付属于持牌金融业务，而PayPal在很多国家没有获得支付牌照，无法进行本地用户间的汇款交易，只好把重心放在跨境支付上，在中国、东南亚和南美洲的大部分市场，PayPal的重心均是跨境支付。 某种意义上，欧美市场以外核心牌照的缺失，也是PayPal交易规模高度依赖美国和欧洲市场的原因。从2018年数据看，PayPal的净收入，54%来自美国，20%来自欧盟（不含英国），11%来自英国，而其他近两百个国家和地区仅贡献不到15%的净收入。 此外，长期在跨境支付市场中摸爬滚打，外汇风险管理能力也成为PayPal差异化竞争力的一部分。2015年之前，PayPal在财务上一直受困于汇率风险，如2014年外汇兑美元损失2500万美元，2013年损失800万美元，之后通过对套期保值等风险对冲工具的灵活应用，PayPal具备了强大的汇率风险管理能力，汇兑损失已无法再对这家国际支付巨头带来威胁。 问题来了，既然现阶段PayPal发力重点仍然是跨境支付，收购国付宝的意义何在呢？最大的意义就是获得了国内支付牌照，可以把跨境支付用户转化为中国境内支付用户，经过三五年的积累，大举发力中国境内市场就有了底气和基础。 对任何一家国际化布局的金融机构来讲，进入中国市场都具有战略重要性，恰逢中国金融市场加大对外开放的时间窗口，对PayPal来讲，此时布局中国市场不需要过多的考虑，无论进入中国市场后取得怎样的成绩，都是后话，进来本身就具有战略意义。 对PayPal如此，对其他国际巨头也是如此。PayPal收购了国付宝，其他国际巨头也不会错失机会。国内有一百多张移动支付牌照，除了头部的几家，多数支付机构日子过得艰辛，大概率也愿意把控制权拱手想让。 所以，对于国内支付市场而言，虽然PayPal入华本身影响有限，但PayPal只是先行者，PayPal之后还有更多的PayPal们要进来。进来的机构多了，无论是国内市场竞争规则，还是国内支付机构的国际化布局，都有了新的想象空间，中国第三方支付市场，自会揭开新的一页。 本文由“洪言微语”原创，作者系苏宁金融研究院院长助理 薛洪言',
        '1、首先，考虑到这位交易员的工作经验，月薪八万五的表述是不正确的：其实是一年的全部薪酬除以12，这个收入是包含年终奖，年终奖在金融行业的很多公司都占据了重要的位置，尤其去年对券商来说整体算不错的年份，所以年终奖不会低，但如果行情不好、券商业绩不好的时候，年终奖也会大打折扣。 2、中金在中资券商里的薪酬体系还是比较向外资靠拢，特点之一就是固定薪酬比较高，而很多券商的固定薪酬是不高的，主要靠年终奖。中金最近几年扩张招了很多人，人员的水准也肯定不如前几年，据说一些新人的合同只签了1年，如果是老人会比较舒服，新人内卷较为严重。这位交易员所在的资管部也是这几年扩招比较厉害的部门之一。 3、国内的交易员类型按照交易的资产类型来分大致可以分为股票交易员、债券交易员（包括资金交易员）、外汇交易员、大宗商品交易员和衍生品交易员。 还有一个划分维度就是交易员自己是否掌握头寸还是只负责按照投资经理的指令进行下单。 如果不掌握头寸只是下单的话其实技术含量不高，比如资管部的股票交易员的工作就是根据投资经理的指令进行准确下单，确保每笔交易符合监管和公司内部制度要求。说实话，可以发挥的空间不大，主要在于细心、准确、不要出错，门槛相对也较低。不过前面也提到了，中金固定薪酬整体比较高。 4、中国的债券市场有别于A股，是机构投资者的天下，这也就使得债券交易员相比股票交易员在询价和报价方面有更多的发挥空间。债券交易员又大概可以分为两大类，一类是资金交易员，一类是现券交易员。 一般刚入门的债券交易员会从资金交易员做起，资金交易员的工作用大白话说就是借钱，在关键时点（比如月末、季末、年底）能借到钱，并且最好能借到你所在机构力所能及能借到的便宜的钱。因为要借钱所以这个活儿还是卖方的性质多一些，适合刚入行的小朋友，逐渐逐渐脸皮就锻炼的厚起来了。 等在交易员的岗位工作1-3年，应该很多人会去做现券的交易员，现券交易员需要对利率债、信用债、衍生品都懂一些，资深的交易员对市场每天、每周的走势也要有自己的预判，甚至对信用债的资质（这决定了好不好交易）也要有自己的判断。因为现券交易员是有买有卖的，尤其是一级市场簿记涉及到竞争性销售，会有一堆券商的债券销售来求，所以不像资金交易员比较苦逼。',
        'ㄟ( ▔, ▔ )ㄏ哪里带来了什么东西啊，除了找到热爱的东西，也失去了很多。听重型现场像疯子一样甩头的时候被家长看到了，然后我就从那个听话懂事的好孩子彻底变成了叛逆违背世俗的坏孩子。可爱的熊熊毛衣和猫猫t恤被换成了死碾核的衣服，比中指讲脏话成为日常。钱都砸在贝斯和各种音源插件宿主上了。家里快成了乐器店，但是啥也不会。 如果生活富足，家庭和睦的话，我大概率只是一个爱电音，可能顺便学学吉他学学简单写电音的小女孩了。每天的日常就是买买买，吃吃吃，认真的看书学习，没什么烦恼。 ㄟ( ▔, ▔ )ㄏ它什么也没给我带来，还加剧了各种压力，只不过是我短暂逃避现实的一个避风港而已。',
        '这个我比较有发言权，我今年21，刚从医院出院半个月，我刚进医院的时候，抱着盆吐血，直径15公分，高13,4公分的痰盂，我吐了半盆，医生都下班了，又被值班护士叫回来了，几个医生围着我，包括重症监护室的医生，商量着把我送到重症监护室，还好我血止住了，不然的话，重症监护室一天3000的费用，我可负担不起',
        '4.24更 麻烦金洲校长在当院士之前，能不能先把这个事情完美解决了  ——————————————————————————— 人在24栋，已经开始隔离。 现在学校比较让我感到不满的是已经开始一刀切了，我一开始是感觉到肚子有点不舒服，然后头有点昏。因为听说了诺如病毒的问题，想着自己去校医院看一下，但是到了校医院就隔离起来了……隔离我的原因是因为发热，37.5度，而我没有检查出肠胃炎……最近也没有到一食堂吃饭。现在感觉学校领导已经开始眉毛胡子一把抓了，没有检查出问题的都是留观隔离三天，4个人住在一起，而四个人住在一起势必会有相互传染的情况。 整个学校现在人心惶惶的，稍微有点发热就会被隔离，校医院现在医疗资源严重不够。我希望学校能够严加审查隔离标准，不要所有人都去24栋隔离三天，并且一直不给学生透露真实情况。 这样下去，学校只会更加人心惶惶，而且医疗资源也会被极大浪费。',
        '我不听！我不听！我不听！ 要真相！要真相！要真相！ 抓舍友！抓舍友！抓舍友！ 有黑幕！有黑幕！有黑幕！ 这体制！这体制！这体制！ 你国怎！你国怎！你国怎！ 家属其实未必不知道死者是自身原因猝死的，伤口是因为从高处摔下来出现的。他们一开始就不接受尸检，声称是法医不“让”尸检。那个法医的话只是建议，并不是强制他们不尸检。而且在事件被他们爆出来以后，死者在医院的救治记录单流出，显示原因是猝死。医院的人再三建议尸检，均被家属拒绝。 学校的处理手法有瑕疵，不够专业，没有最大化考虑家属的心情，没有给出让家属接受的处理方案。双方始终没有达成一致。所以家属就在网上爆料了。 我觉得家属借助网络力量来解决事情，这个出发点没什么可说的。即使家属找学校要一些补偿，我觉得也不能太苛责家属。毕竟失去了一个风华正茂的亲人。 但是家属在第一次发文中，把风向往室友身上带。 非常的无耻。也非常的下作。 和室友有矛盾，据警方透露室友两次口供有差别等等。无一不把矛头指向室友。 第二次发文，家属还发了一张被掐头去尾的聊天记录。就是表明室友影响了死者的休息，双方有矛盾的点。所以还是在影射室友。不管家属说的多么冠冕堂皇。 这个聊天截图，是他弟弟（也就是死者）说室友“他妈的气死我了！”“晚一点打会死吗！” 如果不是经历过多次网络反转事件，导致大部分网友还是能理性客观的看待事情，没有跟风去人肉搜索和网络暴力。 说不定，这个室友就是被网络暴力的对象。 谁又知道，被网络暴力后，这个人会发生什么呢？ 而现实情况是，这个室友发现了死者摔下来，去呼叫外部人力物力来对他进行营救。 结果在家属的描述当中，没有看到一丝一毫的感谢，只有怀疑。 把自己的一己之私的目的的实现途径，捆绑在一个无辜的他人身上。且有可能给这个他人带来严重的伤害，我非常鄙视和唾弃这种行为。',
        '这可是美国的研究成果啊！意义非常重大，值得顶礼膜拜！ 如果你们是冲浪足够久的老网民，你们会发现如果美国搞出一个新技术领先我们，会有很多人出来各种欢腾，各种赞扬，但是这个技术一旦我国攻克，这群人会立马宣扬这个技术多么落后，实现起来多么容易，我国科研工作者多么一般。 因为我国从落后高速发展到现在已经几十年了，从落后到平视再到领先发生在很多领域，所以我也观察到了很多次这种现象，哈哈哈。 有媒体指出，早在2013年BBC就曾报道过，劳伦斯·利弗莫尔实验室宣布实现了首次核聚变反应的净能量增益，实验项目和美国能源部12日的宣传内容几乎一模一样。 对此，《科学》杂志还曾写过一篇论文驳斥BBC虚假宣传，并表示，美国政府的新闻官员没有对互联网上流传的荒诞故事进行核查。《科学》杂志认为这场实验“是一个很好且必要的步骤，但要为人类提供能源还有很长的路要走。” 到了2014年劳伦斯·利弗莫尔实验室再次宣布成功完成净能量增益实验，又找了媒体大张旗鼓地宣传；2021年8月，类似的套路又来了一次，这回实验室还特别发了论文展示成果。 事实上，劳伦斯·利弗莫尔实验室关于核聚变反应的净能量增益早在2013年就已经完成，之后的重复实验只不过是进行复现，其中还有数次实验失败，没有产生数据结果。因此套用一句话说就是，美国能源部炒作的“历史性突破”在原理验证和工程技术没有质变，其中的象征意义和政治意义更加浓厚。 纽约大学新闻学教授、《科学》杂志通讯员查尔斯·塞费在其文章中指出，这不是美国能源部第一次宣布核聚变技术“取得历史性突破”，然而真正的事实是，利弗莫尔实验室的科学家“使用了不同的核聚变点火定义，才得到了一个漂亮的数据。” 塞费还表示，利弗莫尔实验室只谈到他们注入2.05兆焦耳能量，输出3.15兆焦耳能量，却不提输入2.05兆焦耳能量消耗了大约400兆焦耳的电力，这种“收支平衡”的计算没有被考虑在内。另外，塞费指出，利弗莫尔实验室的国家点火设施（NIF）从来就不是核聚变项目，而是专门为武器研究而设计的项目。 有观点认为NIF可以用来研发新型热核武器，这确实是该装置的另一种军事用途，但在技术上更加复杂。相比之下，当前各国使用的传统构型核武器无论在技术、维护成本，还是威力等方面，都要优于使用激光聚变的核武器。 当然，如果跳出NIF的局限性，核聚变技术在军事大有可为，比如磁镜被看好用作核聚变发动机。当前以化学能为动力的火箭发动机，尚不能满足星际航行需要，据科学家推测，航天飞船飞抵距离最近的太阳系外宜居行星，需要6万年时间。如果人类能掌握氦3聚变技术，并将其应用于火箭发动机，那么刘慈欣在《三体》中描述的人类离开太阳系将不是一个遥远的梦想。 如果向近处展望，可控核聚变技术将进一步核反应堆小型化，为航母和武器装备提供更强大的动力。与化石燃料驱动的武器装备相比，小型反应堆将支持全电化武器，尤其是无人作战系统长时间在战场部署。可以设想一些，未来战场上或许将出现搭载小型反应堆的支援单位，为无人机等系统充电的作战模式。 2021年特朗普下台前，还签发了在美国国防领域探索使用小型模块化反应堆的行政命令，可见该技术在未来战场的重要性。 除此之外，激光、电磁炮、微波等新概念武器将颠覆传统作战中武器装备对弹药的依赖，电磁炮投入实战或许指日可待。 目前，世界上实现可控核聚变主要有两条途径，一是磁约束核聚变，就是俗称“人造太阳”的托卡马克装置，迄今公认的聚变能量增益值纪录为 0.67，尚未冲破 1 的平衡点；二是激光聚变点火，即使用高功率激光触发核聚变。 激光约束聚变的典型代表就是上文提到的利弗莫尔实验室的国家点火设施（NIF）。 那么，与美国相比，我国的可控核聚变项目处于什么水平？ 我国的核聚变主要采用托卡马克装置，在这一核聚变领域研究处于世界领先水平。 2020年12月4日14时02分，新一代“人造太阳”装置——中国环流器二号M装置（HL-2M）在成都建成并实现首次放电。 中国环流器二号M装置采用更先进的结构与控制方式，等离子体体积达到国内现有装置2倍以上，等离子体电流能力提高到2.5兆安培以上，等离子体离子温度可达到1.5亿度，能实现高密度、高比压、高自举电流运行 。 这标志着中国自主掌握了大型先进托卡马克装置的设计、建造、运行技术，为我国核聚变堆的自主设计与建造打下坚实基础。 2021年12月我国合肥东方超环实现了1056秒长脉冲高参数等离子体运行，是之前保持记录的2倍还多。 2022年10月20日，中核集团发布消息称，中国新一代“人造太阳”（hl-2m）等离子体电流突破100万安培（1兆安），创造了中国可控核聚变装置运行新纪录，标志着中国核聚变研发距离聚变点火迈进了重要一步，跻身国际第一方阵，技术水平居国际前列。 在激光约束聚变上，我们也取得了长足发展，两条腿走路也不是梦！ 中国科学院上海光学精密机械研究所研究员朱健强，在NIF取得“历史性突破”后透露，目前国内的激光器规模比美国的小，“我们会在三至五年内达到美国点火装置的规模，届时就能开展大规模实验冲击点火，很可能未来三五年就可实现目标”。 NIF使用的点火方案是间接点火，而中国激光聚变装置则采用直接点火。 朱健强透露，中国科学院已于 2020 年成立先导专项，由中科院院士张杰领衔，攻关更加高效的点火技术。这种技术被称为“快点火”，理论上可以使聚变点火所需的能量下降十倍。 我国激光聚变领域泰斗、中国工程院院士范滇元认为，虽然核聚变净能量增益的“ 0 到 1 ”被美国科学家拔得头筹，但将增益率提升到 10、100 的过程中，中国科学家一定会有所建树。 2022年9月14日，《南华早报》做了相关报道，文章中称我国已经着手建设世界上最大的脉冲驱动器，预计2028年将利用核聚变获得能量并网发电。 总而言之，可以对核聚变技术在商业或军事上的应用抱有期待，但美国能源部这次宣传的可控核聚变取得“历史性突破”，则有些过于夸大其词。 来源：美国可控核聚变有突破？骗经费的老套路，自己人都看不下去 核聚变进入可行时代！中国点火成功，只是时间问题',
        '给j外s力递d子的警g.jpg']
    SOURCE:
        ['Zhihu',
        'Zhihu']
    METADATA:
        ['{"question_id": 357137111.0, "answer_id": 914332816.0, "url": "https://www.zhihu.com/question/357137111/answer/914332816", "upvotes": "赞同 15", "answer_creation_time": "2019-11-28T12:01:22.000Z"}',
        '{"question_id": 475169837.0, "answer_id": 2053313113.0, "url": "https://www.zhihu.com/question/475169837/answer/2053313113", "upvotes": "赞同 4432", "answer_creation_time": "2021-08-11T07:26:08.000Z"}',]
        
    """
    def __init__(self, input_path, output_path, dataset_name):
        super(ZhihuFormatHandler, self).__init__(input_path, output_path, dataset_name)
    
    def get_file_list(self) -> list:
        """或取输入路径下的全部文件，可以放一些文件名判断逻辑"""
        files = os.listdir(self.input_path)
        files = [i for i in files if ".parquet" in i]
        return files

    def process_one_file(self, file_path):
        line_count = 0
        jump_count = 0
        
        with open(self.output_path, "a") as fout:
            table = pq.read_table(self.input_path + "/" + file_path)  # encoding?
            data = table.to_pydict()
            instruction = data["INSTRUCTION"]
            response = data["RESPONSE"]
            source = data["SOURCE"]
            metadata = data["METADATA"]
            total_num = len(instruction)
            for i in range(total_num):
                line_count += 1
                md = json.loads(metadata[i])
                # print(md["upvotes"])
                try:
                    upvotes = int(md["upvotes"].replace("赞同 ", ""))
                except Exception as e:
                    upvotes = 0
                    # print("[exception][{}] process metadata upvotes failed: line {} : {}".format(self.dataset_name, md["upvotes"], e))
                    # print(traceback.format_exc())
                if upvotes < 100:  # 只选择高赞回答。
                    jump_count += 1
                    continue
                text = (self.qa2txt(self.zh_process(instruction[i]), self.zh_process(response[i]), "qwen"))
                if not self.quality_assurance(text):
                    jump_count += 1
                    continue
                d = {"text": text}
                fout.write(json.dumps(d, ensure_ascii = False) + "\n")
        return line_count, jump_count

class StarcodeFormatHandler(FormatHandler):
    """example data
    column: 'max_stars_repo_path', 'max_stars_repo_name', 'max_stars_count', 'id', 'content'
    
    max_stars_repo_path
    ['button_events_game.cpp', 'src/core/Variant.cpp', 'src/tracks/ui/SelectHandle.cpp', 'src/logging/log_stream.cc', 'LFFD_ncnn.cpp']
    max_stars_repo_name
    ['darkoppressor/cosmic-runner', 'WilliamTambellini/godopy', 'GitHub87152/audacity', 'xiw2-0/minids', 'Qengineering/LFFD-ncnn-Raspberry-Pi-4']
    max_stars_count
    [0.0, 0.0, 0.0, 3.0, 2.0]
    id
    ['0', '1', '2', '3', '4']
    content
    ['// Copyright (c) 2019 Graphcore Ltd. All rights reserved.\n#include "RandomUtils.hpp"\n\nusing namespace poplar;\n\nnamespace poprand {\n\nclass SetSeedSupervisor : public SupervisorVertexIf<ASM_CODELETS_ENABLED> {\npublic:\n  SetSeedSupervisor();\n\n  Input<Vector<unsigned, ONE_PTR, 8>> seed;\n  const uint32_t seedModifierUser;\n  const uint32_t seedModifierHw;\n\n  IS_EXTERNAL_CODELET(true);\n\n  bool compute() { return true; }\n};\n\n} // namespace poprand\n',
    '\ufeff#include <iostream>\n#include <string>\n#include "point.h"\n#include "cursor.h"\n////////////////////////////////////////////////////////////////////////////////\nPoint Point::setPos(int px, int py)\n{\n    x = px;\n    y = py;\n    return *this;\n}\n////////////////////////////////////////////////////////////////////////////////\nPoint Point::print(string str) const\n{\n    SetCursorPosition(x, y);\n    std::cout << str;\n    return *this;\n}\n////////////////////////////////////////////////////////////////////////////////\nPoint Point::clear(void) const\n{\n    SetCursorPosition(x, y);\n    std::cout << "  ";\n    return *this;\n}\n////////////////////////////////////////////////////////////////////////////////\nPoint Point::setCursorHere(void) const\n{\n    SetCursorPosition(x, y);\n    return *this;\n}\n////////////////////////////////////////////////////////////////////////////////\nPoint Point::move(int movement_x, int movement_y)\n{\n    x += movement_x;\n    y += movement_y;\n    return *this;\n}',
    '#include "system_management.h"\n\nstd::ofstream fileout("log");\n\nSystem_resource::System_resource()\n{\n\tsysinfo(&memInfo);\n\ttotalVirtualMem = memInfo.totalram;\n\ttotalVirtualMem += memInfo.totalswap;\n\ttotalVirtualMem *= memInfo.mem_unit;\n\n\ttotalPhysMem = memInfo.totalram;\n\ttotalPhysMem *= memInfo.mem_unit;\n}\nuint64_t System_resource::getTotalVirtualMem()\n{\n\treturn totalVirtualMem;\n}\nuint64_t System_resource::getVirtualMemUsed()\n{\n\tvirtualMemUsed = memInfo.totalram - memInfo.freeram;\n\tvirtualMemUsed += memInfo.totalswap - memInfo.freeswap;\n\tvirtualMemUsed *= memInfo.mem_unit;\n\treturn virtualMemUsed;\n}\nuint64_t System_resource::getTotalPhysMem()\n{\n\treturn totalPhysMem;\n}\nuint64_t System_resource::getPhysMemUsed()\n{\n\tphysMemUsed = memInfo.totalram - memInfo.freeram;\n\tphysMemUsed *= memInfo.mem_unit;\n\treturn physMemUsed;\n}\nSystem_resource system_resource;\n'
    ]
    
    评价：代码开头的copyright等注释可以考虑去掉。
        有些代码会包含很长的/////////意义不明的字符。
        \n与\t与空格的使用。
    """
    def __init__(self, input_path, output_path, dataset_name, language : list):
        super(StarcodeFormatHandler, self).__init__(input_path, output_path, dataset_name)
        self.language = language
    
    def get_file_list(self) -> list:
        """或取输入路径下的全部文件，可以放一些文件名判断逻辑"""
        files = []
        for lan in self.language:
            path_prefix = self.input_path + "/" + lan
            temp_files = os.listdir(path_prefix)
            temp_files = [path_prefix + "/" + i for i in temp_files if ".parquet" in i]
            files += temp_files
        return files

    def process_one_file(self, file_path):
        line_count = 0
        jump_count = 0
        
        with open(self.output_path, "a") as fout:
            table = pq.read_table(file_path)  # encoding?
            data = table.to_pydict()
            max_stars_repo_path = data["max_stars_repo_path"]
            max_stars_repo_name = data["max_stars_repo_name"]
            max_stars_count = data["max_stars_count"]
            id = data["id"]
            content = data["content"]
            total_num = len(content)    
            for i in range(total_num):
                line_count += 1
                try:
                    stars = int(max_stars_count[i])
                except Exception as e:
                    stars = 0
                    # print("[exception][{}] process max_stars_count failed: line {} : {}".format(self.dataset_name, max_stars_count, e))
                    # print("",traceback.format_exc())
                if stars < 0:  # 只选择高星代码
                    jump_count += 1
                    continue
                text = content[i]
                # text = self.zh_process(content)  # todo，应该针对程序语言进行针对性地清洗
                # if not self.quality_assurance(text):
                #     jump_count += 1
                #     continue
                d = {"text": text}
                fout.write(json.dumps(d, ensure_ascii = False) + "\n")
        return line_count, jump_count

def test_run():
    """简单测试"""
    script_directory = os.path.dirname(os.path.realpath(__file__))
    work_directory = script_directory + "/../download_data/"
    os.chdir(work_directory)
    output_path_root = work_directory + "/output"
    if not os.path.exists(output_path_root):
        os.makedirs(output_path_root)
    
    dataset_handler = {
        "baidu_baike": BaiduBaikeFormatHandler,
        "baidu_QA": BaiduQAFormatHandler,
        "BELLE": BELLEFormatHandler,
        "BELLE_conversations": BELLEConversationsFormatHandler,
        "firefly": FireflyFormatHandler,
        "moss": MossFormatHandler,
        "zhihu": ZhihuFormatHandler,
        "wiki_cn": WikiCNFormatHandler
    }

    for dataset_name, Handler in dataset_handler.items():
        input_path = dataset_name
        if dataset_name == "BELLE_conversations":
            input_path = "BELLE"
        output_path = output_path_root + "/processed_{}.jsonl".format(dataset_name)
        if os.path.exists(output_path):
            os.remove(output_path)
        fh = Handler(input_path, output_path, dataset_name)
        fh.process_all()

    # 代码数据单独处理
    dataset_name = "starcode"
    input_path = dataset_name
    output_path = output_path_root + "/processed_{}.jsonl".format(dataset_name)
    if os.path.exists(output_path):
        os.remove(output_path)
    fh = StarcodeFormatHandler(input_path, output_path, dataset_name, ["cpp", "java", "python"])
    fh.process_all()

def main_run():
    input_path_root = "/data/step0_raw"
    output_path_root = "/data/step1_unified_format"
    if not os.path.exists(output_path_root):
        os.makedirs(output_path_root)

    dataset_process_info = {
        "baidu_baike": (input_path_root + "/baidu_baike", BaiduBaikeFormatHandler),
        "baidu_QA": (input_path_root + "/baidu_wenda", BaiduQAFormatHandler),
        "BELLE_2M": (input_path_root + "/BELLE/2M", BELLEFormatHandler),
        "BELLE_3_5M": (input_path_root + "/BELLE/3_5M", BELLEConversationsFormatHandler),
        "firefly": (input_path_root + "/firefly/train_1M", FireflyFormatHandler),
        "moss": (input_path_root + "/moss", MossFormatHandler),
        "zhihu": (input_path_root + "/zhihu/data", ZhihuFormatHandler),
        "wiki_cn": (input_path_root + "/wiki_cn", WikiCNFormatHandler)
    }

    for dataset_name, info in dataset_process_info.items():
        input_path = info[0]
        Handler = info[1]
        output_path = output_path_root + "/processed_{}.jsonl".format(dataset_name)
        if os.path.exists(output_path):
            os.remove(output_path)
        fh = Handler(input_path, output_path, dataset_name)
        fh.process_all()

    # 代码数据单独处理
    dataset_name = "starcode"
    input_path = input_path_root + "/starcode"
    output_path = output_path_root + "/processed_{}.jsonl".format(dataset_name)
    if os.path.exists(output_path):
        os.remove(output_path)
    fh = StarcodeFormatHandler(input_path, output_path, dataset_name, ["cpp", "java", "python"])
    fh.process_all()


if __name__ == "__main__":
    test_mode = True
    if test_mode:
        test_run()
    else: 
        main_run()



    


    
